home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / BC++ Builder / DATA.Z / IBCTRLS.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-10  |  12.1 KB  |  481 lines

  1. //---------------------------------------------------------------------------
  2. // Borland C++Builder
  3. // Copyright (c) 1987, 1996 Borland International Inc.  All Rights Reserved.
  4. //---------------------------------------------------------------------------
  5. // ibctrls.cpp
  6. // This file is #included in IBREG.CPP which #includes IBREG.H which
  7. // in turn #includes IBCTRLS.H.  Hence #including IBCTRLS.H here is redundant with
  8. // no ramifications (there are sentries in the header file) but has been done
  9. // just to clarify that the function and class implementations in this file are
  10. // prototyped in IBCTRLS.H
  11.  
  12. #if !defined (REGISTER_ALL_CONTROLS)
  13.   #include  "ibctrls.h"
  14. #else
  15.   #include "source\ibctrls.h"
  16. #endif
  17. #pragma resource "*.res"  //Contains the string resource used in this module
  18. #pragma warn -sig
  19. //---------------------------------------------------------------------------
  20. // Dynamically Loaded InterBase API functions (gds32.dll)
  21. TIscQueEvents IscQueEvents;
  22. TIscFree IscFree;
  23. TIscEventBlock IscEventBlock;
  24. TIscEventCounts IscEventCounts;
  25. TIscCancelEvents IscCancelEvents;
  26. TIscInterprete IscInterprete;
  27.  
  28. // TIBComponent class implementation
  29.  
  30. Pointer __fastcall TIBComponent::GetNativeHandle(void)
  31. {
  32.   int length = 0;
  33.   isc_db_handle result = NULL;
  34.   if( FDatabase != NULL  && FDatabase->Connected )
  35.       Check( DbiGetProp( (hDBIObj)FDatabase->Handle, dbNATIVEHNDL,
  36.                         &result, sizeof( isc_db_handle), length ) );
  37.   else
  38.     result = NULL;
  39.  return result;
  40.  }
  41.  
  42.  
  43. void __fastcall TIBComponent::HandleIBErrors(Ibproc32::pstatus_vector status)
  44. {
  45.  
  46.   char buffer[255];
  47.   AnsiString errMsg = " ";
  48.   AnsiString lastMsg;
  49.   isc_status errCode;
  50.  
  51.   do
  52.   {
  53.     errCode = IscInterprete( buffer, &status);
  54.     if( lastMsg != AnsiString( buffer) )
  55.     {
  56.       lastMsg = AnsiString( buffer);
  57.       if( errMsg.Length() !=  0 )
  58.         errMsg = errMsg+"\n";
  59.       errMsg = errMsg+lastMsg;
  60.     }
  61.   } while( errCode != 0 );
  62.   throw EIBError( errMsg );
  63. }
  64.  
  65.  
  66.  
  67.  
  68. bool __fastcall TIBComponent::IsInterbaseDatabase(Db::TDatabase *Database)
  69. {
  70.   bool Result;
  71.   int Length=0;
  72.   char Buffer[63];
  73.  
  74.   Result = false;
  75.   if( Database->Handle != NULL )
  76.   {
  77.     Check(DbiGetProp(hDBIObj(Database->Handle), dbDATABASETYPE, Buffer,
  78.       sizeof(Buffer), Length));
  79.     Result = ( stricmp(Buffer, "INTRBASE" ) == 0 );
  80.   }
  81.   return Result;
  82. }
  83.  
  84.  
  85.  
  86.  
  87.  
  88. void __fastcall TIBComponent::SetDatabase(Db::TDatabase *value)
  89. {
  90.   if( value != FDatabase )
  91.   {
  92.     if( value != NULL && value->Connected )
  93.         ValidateDatabase( value );
  94.     FDatabase = value;
  95.   }
  96. }
  97.  
  98.  
  99.  
  100.  
  101. void __fastcall TIBComponent::ValidateDatabase(Db::TDatabase *Database)
  102. {
  103.   if( Database == NULL  || !Database->Connected  )
  104.           throw EIBError( SInvalidDBConnection );
  105.   else
  106.   {
  107.    if( !IsInterbaseDatabase( Database)  )
  108.     throw EIBError( SInvalidDatabase, new TVarRec( Database->Name ), 1 );
  109.   }
  110. }
  111.  
  112.  
  113.  
  114. __stdcall HandleEvent( int param )
  115. {
  116.   // don't let exceptions propogate out of thread
  117.   try
  118.   {
  119.     ((TIBEventAlerter*)param)->HandleEvent();
  120.   }
  121.   //except
  122.   catch(...)
  123.   {
  124.     Application->HandleException( NULL );
  125.   }
  126.   return 0;
  127. }
  128.  
  129.  
  130.  
  131. #pragma warn -rvl
  132. __cdecl IBEventCallback(Pointer ptr, short length, PChar updated)
  133. {
  134.   DWORD ThreadID=0;
  135.   // Handle events asynchronously in second thread
  136.   EnterCriticalSection(&((TIBEventAlerter*)ptr)->CS);
  137.   ((TIBEventAlerter*)ptr)->UpdateResultBuffer(length, updated);
  138.   CloseHandle( CreateThread( (LPSECURITY_ATTRIBUTES)NULL, (DWORD)8192,
  139.                              (LPTHREAD_START_ROUTINE)HandleEvent,
  140.                              ptr, 0, &ThreadID) );
  141.   LeaveCriticalSection(&((TIBEventAlerter*)ptr)->CS);
  142.  }
  143. #pragma warn .rvl
  144.  
  145.  
  146.  
  147.  
  148.  
  149. __fastcall TIBEventAlerter::TIBEventAlerter( TComponent* AOwner ):TIBComponent( AOwner )
  150. {
  151.   InitializeCriticalSection(&CS);
  152.   FEvents = new TStringList; //.Create;
  153.   ((TStringList*)FEvents)->OnChange = EventChange;
  154.   ((TStringList*)FEvents)->Duplicates = dupIgnore;
  155.  
  156.   // Attempt to load GDS32.DLL.  If this fails then raise an exception.
  157.   // This will cause the component not to be created
  158.   LibHandle = (int) LoadLibrary("gds32.dll");
  159.   if( LibHandle < 32 ) //then
  160.       throw( EDLLLoadError("Unable to load gds32.dll") );
  161.   IscQueEvents = (TIscQueEvents)GetProcAddress((HINSTANCE)LibHandle, "isc_que_events");
  162.   if( IscQueEvents == NULL ) // then            // !!must initialize to NULL?
  163.       throw( EDLLLoadError("Failed to lookup isc_que_events") );
  164.   IscInterprete = (TIscInterprete)GetProcAddress((HINSTANCE)LibHandle, "isc_interprete");
  165.   if( IscInterprete == NULL ) // nil then
  166.       throw EDLLLoadError("Failed to lookup isc_interprete");
  167.  
  168.   IscFree = (TIscFree)GetProcAddress((HINSTANCE)LibHandle, "isc_free");
  169.   if( IscFree ==  NULL ) //nil then
  170.     throw EDLLLoadError("Failed to lookup isc_free");
  171.  
  172.   IscEventBlock = (TIscEventBlock) GetProcAddress((HINSTANCE)LibHandle, "isc_event_block");
  173.   if( IscEventBlock == NULL ) // nil then
  174.      throw EDLLLoadError("Failed to lookup isc_event_block");
  175.  
  176.   IscEventCounts = (TIscEventCounts )GetProcAddress((HINSTANCE)LibHandle, "isc_event_counts");
  177.   if( IscEventCounts == NULL ) // nil then
  178.      throw EDLLLoadError("Failed to lookup isc_event_counts");
  179.  
  180.   IscCancelEvents = (TIscCancelEvents) GetProcAddress((HINSTANCE)LibHandle, "isc_cancel_events");
  181.   if( IscCancelEvents == NULL ) // nil then
  182.       throw EDLLLoadError("Failed to lookup isc_cancel_events");
  183.   }
  184.  
  185.  
  186. __fastcall TIBEventAlerter::~TIBEventAlerter(void)
  187. {
  188.   UnRegisterEvents();
  189.   SetDatabase(NULL);
  190.   ((TStringList*)FEvents)->OnChange = NULL;
  191.   delete FEvents;
  192.   DeleteCriticalSection( &CS);
  193.   if( LibHandle >= 32 )
  194.     FreeLibrary((HINSTANCE)LibHandle);
  195. }
  196.  
  197.  
  198. void __fastcall TIBEventAlerter::CancelEvents(void)
  199. {
  200.   status_vector status;
  201.   isc_status errCode;
  202.   isc_db_handle dbHandle;
  203.  
  204.   if( ProcessingEvents )
  205.       throw EIBError(SInvalidCancellation);
  206.   if( FQueued )
  207.   {
  208.     try
  209.     {
  210.       // wait for event handler to finish before cancelling events
  211.       EnterCriticalSection(&CS);
  212.       ValidateDatabase( Database);
  213.       FQueued = false;
  214.       Changing = true;
  215.       dbHandle = GetNativeHandle();
  216.       errCode = IscCancelEvents( &status, &dbHandle, &EventID);
  217.       if( errCode != 0 )
  218.          HandleIBErrors( &status );
  219.       LeaveCriticalSection(&CS);
  220.     }
  221.     catch( ... ){
  222.       LeaveCriticalSection(&CS);
  223.       throw;
  224.     } //   !!end finally
  225.   } // end Fqued
  226. }
  227.  
  228. void __fastcall TIBEventAlerter::DoQueueEvents(void)
  229. {
  230.   status_vector status;
  231.   isc_status errCode;
  232.   Pointer callback;
  233.   isc_db_handle dbHandle;
  234.  
  235.   ValidateDatabase( Database);
  236.   callback = IBEventCallback;
  237.   dbHandle = GetNativeHandle();
  238.   errCode = IscQueEvents( &status, &dbHandle, &EventID, EventBufferLen,
  239.                           EventBuffer, isc_callback(callback), this);
  240.   if( errCode != 0 )
  241.     HandleIBErrors( &status);
  242.   FQueued = true;
  243.  }
  244.  
  245.  
  246.  
  247. void __fastcall TIBEventAlerter::EventChange(System::TObject *sender)
  248. {
  249.  // check for blank event
  250.  if( ((TStringList*)Events)->IndexOf(" ") !=  -1 )
  251.      throw EIBError( SInvalidEvent);
  252.   // check for too many events
  253.  if( Events->Count > MaxEvents ) //then
  254.  {
  255.     ((TStringList*)Events)->OnChange = NULL;
  256.     Events->Delete( MaxEvents);
  257.     ((TStringList*)Events)->OnChange = EventChange;
  258.     throw EIBError(SMaximumEvents);
  259.  }
  260.  if( Registered )
  261.      RegisterEvents();
  262. }
  263.  
  264.  
  265.  
  266. void __fastcall TIBEventAlerter::HandleEvent(void)
  267. {
  268.   bool CancelAlerts;
  269.   int i;
  270.   status_vector status;
  271.   try
  272.   {
  273.     // prevent modification of vital data structures while handling events
  274.     EnterCriticalSection(&CS);
  275.     ProcessingEvents = true;
  276.     IscEventCounts( &status, EventBufferLen, EventBuffer, ResultBuffer);
  277.     CancelAlerts = false;
  278.     if( FOnEventAlert != NULL && !Changing )
  279.     {
  280.        for( i = 0; i < Events->Count; i++ ) // do
  281.        {
  282.          try
  283.          {
  284.            if(status[i] != 0 && !CancelAlerts ) //then
  285.              FOnEventAlert( this,
  286.                             Events->Strings[Events->Count-i-1],
  287.                             status[i],
  288.                             CancelAlerts);
  289.          }
  290.          catch(...) //except
  291.          {
  292.            Application->HandleException( NULL);
  293.          }
  294.        }
  295.     }
  296.     Changing = false;
  297.     if( !CancelAlerts && FQueued ) //then
  298.         DoQueueEvents();
  299.     ProcessingEvents = false;
  300.     LeaveCriticalSection(&CS);
  301.   } //  end try
  302.   catch(...)
  303.   {
  304.     ProcessingEvents = false;
  305.     LeaveCriticalSection(&CS);
  306.     throw;
  307.   }  //  end finally?
  308. }
  309.  
  310.  
  311.  
  312. void __fastcall TIBEventAlerter::Loaded(void)
  313. {
  314.   TIBComponent::Loaded();
  315.   try
  316.   {
  317.    if( RegisteredState ) //then
  318.      RegisterEvents();
  319.    }
  320.   catch(...)//  except
  321.   {
  322.     if( ComponentState.Contains( csDesigning ) )
  323.       Application->HandleException( this );
  324.     else
  325.       throw;
  326.   }
  327. }
  328.  
  329.  
  330. void __fastcall TIBEventAlerter::Notification(Classes::TComponent *AComponent, Classes::TOperation Operation )
  331. {
  332.   TIBComponent::Notification( AComponent, Operation);
  333.   if( Operation == opRemove && AComponent == Database)// then
  334.   {
  335.     UnRegisterEvents();
  336.     Database = NULL;
  337.   }
  338. }
  339.  
  340.  
  341.  
  342. void __fastcall TIBEventAlerter::QueueEvents(void)
  343. {
  344.   if( !FRegistered ) //then
  345.     throw EIBError( SNoEventsRegistered);
  346.   if( ProcessingEvents ) //then
  347.     throw EIBError( SInvalidQueueing);
  348.   if( !FQueued ) //then
  349.   {
  350.     try
  351.       // wait until current event handler is finished before queuing events
  352.     {
  353.       EnterCriticalSection( &CS);
  354.       DoQueueEvents();
  355.       Changing = true;
  356.       LeaveCriticalSection( &CS);
  357.     }
  358.     catch(...)
  359.     {
  360.       LeaveCriticalSection( &CS);
  361.       throw;
  362.     }
  363.   }
  364. }
  365.  
  366.  
  367.  
  368. void __fastcall TIBEventAlerter::RegisterEvents(void)
  369. {
  370.   ValidateDatabase( Database);
  371.   if( ComponentState.Contains( csDesigning )  )
  372.     FRegistered = true;
  373.   else
  374.   {
  375.     UnRegisterEvents();
  376.     if( Events->Count == 0 )
  377.        return;
  378.     for(int i = 0; i < Events->Count; i++ )
  379.       strcpy( Buffer[i], Events->Strings[i].c_str());
  380.  
  381.     EventBufferLen = IscEventBlock(&EventBuffer,
  382.                                    &ResultBuffer,
  383.                                    Events->Count,
  384.                                    Buffer[0]);
  385.  
  386.     //Below is how one would more thoroughly call IscEventBlock
  387.     //to supply multiple string pointers on the stack.  The above method
  388.     //only does one.
  389.     /*
  390.     asm
  391.     {
  392.       mov ecx, dword ptr [i]
  393.       mov eax, dword ptr [bufptr]
  394.       @@1:
  395.       push eax
  396.       add  eax, EventLength
  397.       loop @@1
  398.       push dword ptr [i]
  399.       push dword ptr [resultBufPtr]
  400.       push dword ptr [eventBufPtr]
  401.       call [IscEventBlock]
  402.       mov  dword ptr [buflen], eax
  403.       mov eax, dword ptr [i]
  404.       shl eax, 2
  405.       add eax, 12
  406.       add esp, eax
  407.      }*/ // end asm block
  408.     FRegistered = true;
  409.     QueueEvents();
  410.   }
  411. }
  412. #pragma warn .sig
  413.  
  414.  
  415.  
  416.  
  417. void __fastcall TIBEventAlerter::SetEvents(Classes::TStrings *value)
  418. {
  419.   FEvents->Assign(value);
  420. }
  421.  
  422.  
  423. void __fastcall TIBEventAlerter::SetDatabase(Db::TDatabase *value)
  424. {
  425.   if( value != Database )
  426.   {
  427.     UnRegisterEvents();
  428.     if( value != NULL  && value->Connected ) //!!assigned?
  429.        ValidateDatabase( value);
  430.     Database = value;
  431.   }
  432. }
  433.  
  434.  
  435.  
  436. void __fastcall TIBEventAlerter::SetRegistered( bool value )
  437. {
  438.   if( ComponentState.Contains ( csReading  ) )
  439.     RegisteredState = value;
  440.   else
  441.     if( FRegistered != value )
  442.       if( value )
  443.         RegisterEvents();
  444.       else
  445.         UnRegisterEvents();
  446. }
  447.  
  448.  
  449.  
  450. void __fastcall TIBEventAlerter::UnRegisterEvents(void)
  451. {
  452.   if( ProcessingEvents )
  453.      throw EIBError( SInvalidRegistration);
  454.   if( ComponentState.Contains( csDesigning  ) )
  455.     FRegistered = false;
  456.   else
  457.    if( ComponentState.Contains( csLoading  ) != true )
  458.    {
  459.     CancelEvents();
  460.     if( FRegistered )
  461.     {
  462.       IscFree( EventBuffer);
  463.       EventBuffer = NULL;
  464.       IscFree( ResultBuffer);
  465.       ResultBuffer = NULL;
  466.     }
  467.     FRegistered = false;
  468.    }
  469. }
  470.  
  471.  
  472. void __fastcall TIBEventAlerter::UpdateResultBuffer(int length, System::PChar updated)
  473. {
  474.   int i;
  475.   for( i = 0; i < length; i++ )
  476.     ResultBuffer[i] = updated[i];
  477. }
  478.  
  479.  
  480.  
  481.